[{"id":"1ed419df.9ad846","type":"subflow","name":"0 / 1","info":"","category":"heatweb","in":[{"x":60,"y":96,"wires":[{"id":"7388fdf3.0be844"}]}],"out":[{"x":561,"y":80,"wires":[{"id":"7305e28e.f43554","port":0},{"id":"43b14e16.7b35e8","port":0}]}],"env":[]},{"id":"7388fdf3.0be844","type":"switch","z":"1ed419df.9ad846","name":"on / off","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"str"},{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"run","vt":"str"},{"t":"true"},{"t":"else"}],"checkall":"false","repair":false,"outputs":6,"x":200,"y":96,"wires":[["7305e28e.f43554"],["7305e28e.f43554"],["7305e28e.f43554"],["7305e28e.f43554"],["7305e28e.f43554"],["43b14e16.7b35e8"]]},{"id":"7305e28e.f43554","type":"change","z":"1ed419df.9ad846","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"1","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":401,"y":80,"wires":[[]]},{"id":"43b14e16.7b35e8","type":"change","z":"1ed419df.9ad846","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"0","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":402,"y":128,"wires":[[]]},{"id":"512e2cc3.3a1bdc","type":"tab","label":"heatweb","disabled":false,"info":"https://docs.npmjs.com/misc/developers\n\nhttps://nodered.org/docs/creating-nodes/first-node#testing-your-node-in-node-red\n\n\n\nReadings: http://localhost:8080/api/readings\n\nHistory: http://localhost:8080/api/history\n\nTopics: http://localhost:8080/api/topics\n\n\nhttps://stackoverflow.com/questions/7650071/is-there-a-way-to-create-a-function-from-a-string-with-javascript"},{"id":"d214642e.b6396","type":"heatwebNode","z":"512e2cc3.3a1bdc","name":"","nodeConfig":"","proxy1Name":"RHG PC","proxy1Address":"192.168.0.223:8080","x":483.33331298828125,"y":149.33331298828125,"wires":[["90205dda.22a07"]]},{"id":"90205dda.22a07","type":"debug","z":"512e2cc3.3a1bdc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":777.3333129882812,"y":149.33331298828125,"wires":[]},{"id":"1e25bdf7.138ce2","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180.33331298828125,"y":149.33331298828125,"wires":[["d214642e.b6396"]]},{"id":"38591df6.8c460a","type":"debug","z":"512e2cc3.3a1bdc","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":733.1348075866699,"y":851.0278186798096,"wires":[]},{"id":"6a6c7478.9afd54","type":"mqtt out","z":"512e2cc3.3a1bdc","name":"mqtt.heatweb.com","topic":"","qos":"0","retain":"false","broker":"5fa73555.16541c","x":772.1347618103027,"y":990.0277690887451,"wires":[]},{"id":"a7692fdf.94f9a8","type":"debug","z":"512e2cc3.3a1bdc","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":751.1347618103027,"y":952.0277690887451,"wires":[]},{"id":"50109303.1b6924","type":"mqtt out","z":"512e2cc3.3a1bdc","name":"mqtt localhost","topic":"","qos":"0","retain":"false","broker":"b650ce61.a54ba","x":763.1348075866699,"y":888.0278186798096,"wires":[]},{"id":"da238935.19dfb","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"disconnect","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":"30","x":424.33331298828125,"y":495.33331298828125,"wires":[["f275f537.89c3b"]],"icon":"font-awesome/fa-chain-broken"},{"id":"514d5349.255974","type":"debug","z":"512e2cc3.3a1bdc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":908,"y":386,"wires":[]},{"id":"3e297b4b.ea0b8c","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"port","payload":"1880","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":199.33331298828125,"y":347.33331298828125,"wires":[["f275f537.89c3b"]],"info":"Open remote access to Node-RED."},{"id":"a24b1251.c78408","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"port","payload":"80","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":208.33331298828125,"y":424.33331298828125,"wires":[["f275f537.89c3b"]]},{"id":"46881022.88ba6","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"port","payload":"9090","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":198.33331298828125,"y":492.33331298828125,"wires":[["f275f537.89c3b"]]},{"id":"22b79bdf.56f684","type":"link in","z":"512e2cc3.3a1bdc","name":"handler","links":["c52fbb57.bac4f","ba8f0c02.aabab8","37573184.b4070e","a2938123.53886","5b0110f7.cc3768","a7f56b83.82839","20aa6e2b.1ebf12"],"x":224.13479614257812,"y":781.0278091430664,"wires":[["2768d003.cee6c"]]},{"id":"b4b7228c.619648","type":"ui_gauge","z":"512e2cc3.3a1bdc","name":"","group":"e80025eb.47b288","order":3,"width":"4","height":"4","gtype":"gage","title":"{{msg.topic}}","label":"{{msg.units}}","format":"{{value}}","min":0,"max":"100","colors":["#507adc","#eff34e","#ca3838"],"seg1":"","seg2":"","x":855.2539138793945,"y":2034.9759216308594,"wires":[]},{"id":"62062de2.37807c","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"dat/tH","payload":"readings.local.phex1.dat.tDiff","payloadType":"global","repeat":"3","crontab":"","once":false,"onceDelay":0.1,"x":279.25391387939453,"y":2042.9759140014648,"wires":[["53d29c93.4d8bfc"]]},{"id":"53d29c93.4d8bfc","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"units","pt":"msg","to":"payload.units","tot":"msg"},{"t":"set","p":"topic","pt":"msg","to":"payload.title","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"payload.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":624.2539138793945,"y":2042.9759140014648,"wires":[["b4b7228c.619648","2d24ce5e.3797d2"]]},{"id":"2e52c84c.9c6588","type":"comment","z":"512e2cc3.3a1bdc","name":"A Heatweb Connect Node is used to establish data services, rest api, and user interface. The node retreives the default dictionary describing data from Heatweb.","info":"","x":592.3333129882812,"y":47.33331298828125,"wires":[]},{"id":"ef93e77e.732898","type":"comment","z":"512e2cc3.3a1bdc","name":"A single Heatweb Remote Node establishes an MQTT link to Heatweb for receiving commands, including opening a remote connection to Node-RED or other ports using ngrok. ","info":"","x":629.3333129882812,"y":228.33331298828125,"wires":[]},{"id":"7c2088f0.3ad498","type":"comment","z":"512e2cc3.3a1bdc","name":"Heatweb Handler Nodes are used to capture data, overlay additional information, remove repeat messages, and limit message throughput to external servers.","info":"","x":583.6666412353516,"y":556.0000305175781,"wires":[]},{"id":"b353708e.3d3b68","type":"comment","z":"512e2cc3.3a1bdc","name":"All data is stored in the global readings object according to: network / device / data type / key = objectcontaining value, timestamps & other captured data","info":"","x":570.2538986206055,"y":1973.97598361969,"wires":[]},{"id":"c52fbb57.bac4f","type":"link out","z":"512e2cc3.3a1bdc","name":"","links":["22b79bdf.56f684"],"x":853,"y":427,"wires":[]},{"id":"f753d032.7028a","type":"comment","z":"512e2cc3.3a1bdc","name":"Standard tags can be added to messages including, title, units, points (number of historic data points to keep in memory), and deadband","info":"","x":525.6190185546875,"y":1511.2617492675781,"wires":[]},{"id":"3c21647e.11be74","type":"comment","z":"512e2cc3.3a1bdc","name":"Stored data can be republished via a request command to a Handling Node, where the topic is ending in .../cmd/request","info":"","x":462.674560546875,"y":655.3452758789062,"wires":[]},{"id":"cbc2ca22.84b22","type":"comment","z":"512e2cc3.3a1bdc","name":"The request payload should be a 5 level MQTT style filter, such as +/+/+/settings/# or local/+/boiler1/#","info":"","x":402.674560546875,"y":684.6786499023438,"wires":[]},{"id":"5ca194ac.efc1a4","type":"comment","z":"512e2cc3.3a1bdc","name":"Messages are only sent to the external output of the node, and the original request message is not passed through.","info":"","x":442.674560546875,"y":722.6786499023438,"wires":[]},{"id":"435a820b.aa028c","type":"comment","z":"512e2cc3.3a1bdc","name":"All messages (except some commands) are passed through to the internal output with additional information added. The external outout is filtered.","info":"","x":543.6666412353516,"y":586.0000305175781,"wires":[]},{"id":"e2d838ae.328e","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"local/TestNode1/TestNode1/cmd/request","payload":"+/+/phex1/#","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":171.1348114013672,"y":852.0277900695801,"wires":[["2768d003.cee6c"]]},{"id":"2e25eb7.5134994","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"local/TestNode1/TestNode1/cmd/sync","payload":"+/+/phex1/#","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":173.1348114013672,"y":931.0277900695801,"wires":[["2768d003.cee6c"]]},{"id":"7828f01e.af8878","type":"mqtt in","z":"512e2cc3.3a1bdc","name":"TestNode1/cmd/#","topic":"testingRemoteConnection/+/TestNode1/cmd/#","qos":"0","datatype":"auto","broker":"5fa73555.16541c","x":163.13481521606445,"y":980.0277919769287,"wires":[["2768d003.cee6c"]]},{"id":"d421bc1f.e1b0b","type":"comment","z":"512e2cc3.3a1bdc","name":"Topics are conditioned according to the Heatweb 5 Tier Protocol:  network / publisher / device / data type / key = value","info":"","x":453.66664123535156,"y":615.0000305175781,"wires":[]},{"id":"1f882dd1.f41ee2","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"port","payload":"8080","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":198.33331298828125,"y":380.33331298828125,"wires":[["f275f537.89c3b"]]},{"id":"970f7711.3e0a4","type":"comment","z":"512e2cc3.3a1bdc","name":"A web server is created on port 8080 for http and 8443 for https. Readings can be viewed on http://localhost:8080/api/readings.","info":"","x":481.33331298828125,"y":78.33331298828125,"wires":[]},{"id":"30476ff7.5748a8","type":"comment","z":"512e2cc3.3a1bdc","name":"Additional information can be set using msg.attributes object.  If the message topic does not refer to a device then global.node will ne used.","info":"","x":525.2857131958008,"y":1540.9284362792969,"wires":[]},{"id":"2768d003.cee6c","type":"heatwebFilter","z":"512e2cc3.3a1bdc","name":"","nodeConfig":"","resetEvery":"86400","defaultGroup":"dat","defaultPoints":"15","deadband":"","storeHistoricEx":false,"x":481.13482666015625,"y":876.0277709960938,"wires":[["38591df6.8c460a","50109303.1b6924","bee9cbcf.345a5","40c934ad.959abc"],["6a6c7478.9afd54","a7692fdf.94f9a8"]]},{"id":"f275f537.89c3b","type":"heatwebRemote","z":"512e2cc3.3a1bdc","name":"","nodeConfig":"","timeout":"15","x":631,"y":385,"wires":[["514d5349.255974","c52fbb57.bac4f"]]},{"id":"d0d7757a.cffa98","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"port","payload":"8443","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":198,"y":458,"wires":[["f275f537.89c3b"]]},{"id":"15e7e13b.ff313f","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"local/TestNode1/TestNode1/cmd/request","payload":"local/#","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190.46817016601562,"y":816.0278091430664,"wires":[["2768d003.cee6c"]]},{"id":"ed2d7d2a.0c4a7","type":"inject","z":"512e2cc3.3a1bdc","name":"fH","topic":"dat/fH","payload":"5","payloadType":"num","repeat":"45","crontab":"","once":true,"onceDelay":0.1,"x":188.00000762939453,"y":1792.4999694824219,"wires":[["a4329a63.fc4aa8"]]},{"id":"98a825ca.e259f","type":"inject","z":"512e2cc3.3a1bdc","name":"tHo","topic":"tHo","payload":"46","payloadType":"num","repeat":"60","crontab":"","once":true,"onceDelay":0.1,"x":188.00000762939453,"y":1752.4999694824219,"wires":[["345ed2ae.6e3fce"]]},{"id":"1e88f534.538bc3","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"phex1/dat/tHo","tot":"str"},{"t":"set","p":"points","pt":"msg","to":"500","tot":"num"},{"t":"set","p":"deadband","pt":"msg","to":"0.5","tot":"num"},{"t":"set","p":"attributes","pt":"msg","to":"{\"units\":\"°C\",\"title\":\"Common Return Temperature\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":626.0000076293945,"y":1752.4999694824219,"wires":[["6108b7a6.0a696"]]},{"id":"6108b7a6.0a696","type":"link out","z":"512e2cc3.3a1bdc","name":"","links":["cca4d4f8.5f0af8"],"x":971.8889236450195,"y":1826.0552673339844,"wires":[]},{"id":"345ed2ae.6e3fce","type":"function","z":"512e2cc3.3a1bdc","name":"random 20-40","func":"\nmsg.payload = 20 + (Math.floor(Math.random() * 200)/10);\n\nreturn msg;","outputs":1,"noerr":0,"x":378.00000762939453,"y":1752.4999694824219,"wires":[["1e88f534.538bc3"]]},{"id":"a4329a63.fc4aa8","type":"function","z":"512e2cc3.3a1bdc","name":"random 0-20","func":"\nmsg.payload = (Math.floor(Math.random() * 200)/10);\n\nreturn msg;","outputs":1,"noerr":0,"x":368.00000762939453,"y":1792.4999694824219,"wires":[["9a6b6101.fcc098"]]},{"id":"9a6b6101.fcc098","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"phex1/dat/fH","tot":"str"},{"t":"set","p":"points","pt":"msg","to":"500","tot":"num"},{"t":"set","p":"deadband","pt":"msg","to":"0.2","tot":"num"},{"t":"set","p":"attributes","pt":"msg","to":"{\"units\":\"lpm\"}","tot":"json"},{"t":"set","p":"title","pt":"msg","to":"Primary flow rate","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":626.0000076293945,"y":1792.4999694824219,"wires":[["6108b7a6.0a696"]]},{"id":"bee9cbcf.345a5","type":"link out","z":"512e2cc3.3a1bdc","name":"","links":["747b48c2.793a6","9ebc913e.238a6"],"x":699.334789276123,"y":774.5278415679932,"wires":[]},{"id":"40c934ad.959abc","type":"debug","z":"512e2cc3.3a1bdc","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":752.9443473815918,"y":815.6112461090088,"wires":[]},{"id":"a2938123.53886","type":"link out","z":"512e2cc3.3a1bdc","name":"","links":["22b79bdf.56f684"],"x":909,"y":1240,"wires":[]},{"id":"cca4d4f8.5f0af8","type":"link in","z":"512e2cc3.3a1bdc","name":"handleWithCalculations","links":["7642a9dd.77e12","9e8f006b.48179","6108b7a6.0a696","3f89e4e2.2899bc","63d276c2.9eddf8"],"x":242.72222900390625,"y":1238.777587890625,"wires":[["25da332b.be35fc"]]},{"id":"ee481e50.d5271","type":"inject","z":"512e2cc3.3a1bdc","name":"tH","topic":"tH","payload":"46","payloadType":"num","repeat":"120","crontab":"","once":true,"onceDelay":0.1,"x":192.00000762939453,"y":1703.4999694824219,"wires":[["910e4503.a8169"]]},{"id":"c444b6d3.a68128","type":"change","z":"512e2cc3.3a1bdc","name":"phex1","rules":[{"t":"set","p":"topic","pt":"msg","to":"phex1/dat/tH","tot":"str"},{"t":"set","p":"points","pt":"msg","to":"500","tot":"num"},{"t":"set","p":"deadband","pt":"msg","to":"0.5","tot":"num"},{"t":"set","p":"attributes","pt":"msg","to":"{\"units\":\"°C\",\"title\":\"Primary Flow Temperature\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":595.0000076293945,"y":1676.4999694824219,"wires":[["47608a0f.ed068c"]]},{"id":"910e4503.a8169","type":"function","z":"512e2cc3.3a1bdc","name":"random 70-95","func":"\nmsg.payload = 70 + (Math.floor(Math.random() * 250)/10);\n\nreturn msg;","outputs":1,"noerr":0,"x":377.00000762939453,"y":1703.4999694824219,"wires":[["8c6eb531.62e408","c444b6d3.a68128","258ed5d3.10073a"]]},{"id":"e9180cf5.6b7ac","type":"ui_gauge","z":"512e2cc3.3a1bdc","name":"","group":"e80025eb.47b288","order":3,"width":"4","height":"4","gtype":"gage","title":"{{msg.topic}}","label":"{{msg.units}}","format":"{{value}}","min":0,"max":"100","colors":["#507adc","#eff34e","#ca3838"],"seg1":"","seg2":"","x":854.8571243286133,"y":2112.2142028808594,"wires":[]},{"id":"64555d72.c2d92c","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"dat/tH","payload":"readings.local.phex1.stat.vwatHo24","payloadType":"global","repeat":"3","crontab":"","once":false,"onceDelay":0.1,"x":297.8571243286133,"y":2098.2142028808594,"wires":[["f4fb5f66.d6ea4"]]},{"id":"f4fb5f66.d6ea4","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"units","pt":"msg","to":"payload.units","tot":"msg"},{"t":"set","p":"topic","pt":"msg","to":"payload.title","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"payload.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":622.8571243286133,"y":2098.2142028808594,"wires":[["e9180cf5.6b7ac","2d24ce5e.3797d2"]]},{"id":"2d24ce5e.3797d2","type":"ui_chart","z":"512e2cc3.3a1bdc","name":"","group":"e80025eb.47b288","order":5,"width":"24","height":"5","label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":854.8571243286133,"y":2073.4642028808594,"wires":[[]]},{"id":"9a45da0e.16d9a","type":"inject","z":"512e2cc3.3a1bdc","name":"Standard Calculations","topic":"calculations","payload":"[{\"topic\":\"stat/vwatCo24\",\"filter\":\"+/+/+/dat/#\",\"function\":\"weightedAverage\",\"save\":\"daily\",\"wipe\":\"daily\",\"parameters\":[\"dat/tCo\",\"dat/fC\"],\"title\":\"Volume weighted average tap temp for today\",\"units\":\"°C\",\"points\":365,\"deadband\":0.5},{\"topic\":\"stat/vwatHo24\",\"filter\":\"+/+/+/dat/#\",\"function\":\"weightedAverage\",\"save\":\"daily\",\"wipe\":\"daily\",\"parameters\":[\"dat/tHo\",\"dat/fH\"],\"title\":\"Volume weighted average return temp for today\",\"units\":\"°C\",\"points\":365,\"deadband\":0.5},{\"topic\":\"stat/vwatH24\",\"filter\":\"+/+/+/dat/#\",\"function\":\"weightedAverage\",\"save\":\"daily\",\"wipe\":\"daily\",\"parameters\":[\"dat/tH\",\"dat/fH\"],\"title\":\"Volume weighted average flow temp for today\",\"units\":\"°C\",\"points\":365,\"deadband\":0.5},{\"topic\":\"stat/vH24\",\"filter\":\"+/+/+/dat/#\",\"function\":\"integrate\",\"save\":\"daily\",\"wipe\":\"daily\",\"parameters\":[\"dat/fH\",60],\"title\":\"Primary volume for today\",\"units\":\"litres\",\"points\":365,\"deadband\":5},{\"topic\":\"stat/vC24\",\"filter\":\"+/+/+/dat/#\",\"function\":\"integrate\",\"save\":\"daily\",\"wipe\":\"daily\",\"parameters\":[\"dat/fC\",60],\"title\":\"Tap volume for today\",\"units\":\"litres\",\"points\":365,\"deadband\":1},{\"topic\":\"dat/tDiff\",\"filter\":\"+/+/+/dat/#\",\"eval\":\"function (a, b) { return a - b; }\",\"parameters\":[\"tH\",\"tHo\"],\"title\":\"Primary temperature drop\",\"units\":\"°C\",\"deadband\":0.5},{\"topic\":\"dat/kwH\",\"filter\":\"+/+/+/dat/#\",\"eval\":\"function (a, b, c) { return 4.2 * (a - b) * (c/60); }\",\"parameters\":[\"tH\",\"tHo\",\"fH\"],\"title\":\"Primary Power\",\"units\":\"kW\",\"deadband\":1},{\"topic\":\"stat/kwhH24\",\"filter\":\"+/+/+/dat/#\",\"function\":\"integrate\",\"parameters\":[\"dat/kwH\",3600],\"wipe\":\"daily\",\"title\":\"Primary Energy for today\",\"units\":\"kWh\",\"deadband\":0.1},{\"topic\":\"meter/tDiff\",\"filter\":\"+/+/+/meter/#\",\"eval\":\"function (a, b) { return a - b; }\",\"parameters\":[\"tF\",\"tR\"],\"title\":\"Primary temperature drop\",\"units\":\"°C\"},{\"topic\":\"stat/vwatR24\",\"filter\":\"+/+/+/meter/#\",\"function\":\"weightedAverage\",\"save\":\"daily\",\"wipe\":\"daily\",\"parameters\":[\"meter/tR\",\"dat/fR\"],\"title\":\"Volume weighted average return temp for today (meter)\",\"units\":\"°C\",\"points\":365,\"deadband\":0.5},{\"topic\":\"tDiff\",\"filter\":\"+/+/+/dat/#\",\"eval\":\"function (a, b) { return a - b; }\",\"parameters\":[\"tIn\",\"tOut\"],\"title\":\"Primary temperature drop\",\"units\":\"°C\"}]","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":"0","x":640.5,"y":1185.75,"wires":[["78681304.643d1c"]]},{"id":"53c58bff.1dfbac","type":"comment","z":"512e2cc3.3a1bdc","name":"Calculation descriptions are stored in a Calculations Node, by injecting with the topic 'calculations' or can be stored in flow.calculations, or global.calculations","info":"","x":574.5,"y":1073.25,"wires":[]},{"id":"99c83dd5.917f9","type":"comment","z":"512e2cc3.3a1bdc","name":"Incoming messages are checked against calculations, which are then performed and sent as additional messages.","info":"","x":444.5,"y":1109.5,"wires":[]},{"id":"26de6b3f.6399fc","type":"heatwebCalc","z":"512e2cc3.3a1bdc","name":"","x":716,"y":1240,"wires":[["a2938123.53886"]]},{"id":"8d911abd.8279f","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"local/TestNode1/TestNode1/cmd/sync","payload":"local/#","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":"60","x":191.99998474121094,"y":896.0000190734863,"wires":[["2768d003.cee6c"]]},{"id":"78681304.643d1c","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"calculations","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":873,"y":1186,"wires":[[]]},{"id":"5b0110f7.cc3768","type":"link out","z":"512e2cc3.3a1bdc","name":"","links":["22b79bdf.56f684"],"x":590.8571090698242,"y":2305.2143869400024,"wires":[]},{"id":"f54b0030.32b53","type":"inject","z":"512e2cc3.3a1bdc","name":"Setup phex1 commands","topic":"phex1/json/commands","payload":"[{\"topic\":\"phex1/cmd/run\",\"title\":\"Run\",\"default\":\"1\"},{\"topic\":\"phex1/cmd/run\",\"title\":\"Turn Off\",\"default\":\"0\"}]","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":240.85712432861328,"y":2305.214324951172,"wires":[["bff2b031.2984d8"]]},{"id":"bff2b031.2984d8","type":"json","z":"512e2cc3.3a1bdc","name":"","property":"payload","action":"str","pretty":false,"x":460.8571243286133,"y":2305.214324951172,"wires":[["5b0110f7.cc3768"]]},{"id":"de70c7ed.987f6","type":"comment","z":"512e2cc3.3a1bdc","name":"Device commands can be registered via the json/commands topic. The payload should be a JSON string.","info":"","x":419.85713958740234,"y":2240.2142629623413,"wires":[]},{"id":"c22a56f0.3c9db","type":"comment","z":"512e2cc3.3a1bdc","name":"Internal feed, includes external commands","info":"","x":890,"y":773,"wires":[]},{"id":"fb8f7eb4.935b28","type":"mqtt in","z":"512e2cc3.3a1bdc","name":"","topic":"+/+/phex1/cmd/#","qos":"0","datatype":"auto","broker":"b650ce61.a54ba","x":209.85713958740234,"y":2428.2142629623413,"wires":[["cbef0bf8.b55758"]]},{"id":"cbef0bf8.b55758","type":"switch","z":"512e2cc3.3a1bdc","name":"","property":"topic","propertyType":"msg","rules":[{"t":"cont","v":"cmd/run","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":399.85713958740234,"y":2428.2142629623413,"wires":[["630e662.f534a18"],[]]},{"id":"134fa658.df1c82","type":"ui_chart","z":"512e2cc3.3a1bdc","name":"","group":"e80025eb.47b288","order":5,"width":"24","height":"5","label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":854.8571243286133,"y":2155.2142028808594,"wires":[[]]},{"id":"d52f129d.e31638","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"stat/kwhH24","payload":"readings.local.phex1.stat.kwhH24","payloadType":"global","repeat":"3","crontab":"","once":false,"onceDelay":0.1,"x":293.8571243286133,"y":2155.2142028808594,"wires":[["a610d881.063a28"]]},{"id":"a610d881.063a28","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"units","pt":"msg","to":"payload.units","tot":"msg"},{"t":"set","p":"topic","pt":"msg","to":"payload.title","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"payload.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":623.8571243286133,"y":2155.2142028808594,"wires":[["134fa658.df1c82"]]},{"id":"b7ad516f.0ac22","type":"function","z":"512e2cc3.3a1bdc","name":"random 20-40","func":"\nmsg.payload = 20 + (Math.floor(Math.random() * 200)/10);\n\nreturn msg;","outputs":1,"noerr":0,"x":378.00000762939453,"y":1832.4999694824219,"wires":[["85c92cdc.e9f268"]]},{"id":"86e61f7.412ba6","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"phex2/dat/fH","tot":"str"},{"t":"set","p":"points","pt":"msg","to":"500","tot":"num"},{"t":"set","p":"deadband","pt":"msg","to":"0.2","tot":"num"},{"t":"set","p":"attributes","pt":"msg","to":"{\"units\":\"lpm\"}","tot":"json"},{"t":"set","p":"title","pt":"msg","to":"Primary flow rate","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":626.0000076293945,"y":1872.4999694824219,"wires":[["6108b7a6.0a696"]]},{"id":"85c92cdc.e9f268","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"phex2/dat/tHo","tot":"str"},{"t":"set","p":"points","pt":"msg","to":"500","tot":"num"},{"t":"set","p":"deadband","pt":"msg","to":"0.5","tot":"num"},{"t":"set","p":"attributes","pt":"msg","to":"{\"units\":\"°C\",\"title\":\"Common Return Temperature\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":626.0000076293945,"y":1832.4999694824219,"wires":[["6108b7a6.0a696"]]},{"id":"84602ba7.9c836","type":"function","z":"512e2cc3.3a1bdc","name":"random 0-20","func":"\nmsg.payload = (Math.floor(Math.random() * 200)/10);\n\nreturn msg;","outputs":1,"noerr":0,"x":368.00000762939453,"y":1872.4999694824219,"wires":[["86e61f7.412ba6"]]},{"id":"3f914913.74810e","type":"inject","z":"512e2cc3.3a1bdc","name":"tHo","topic":"tHo","payload":"46","payloadType":"num","repeat":"99","crontab":"","once":true,"onceDelay":0.1,"x":188.00000762939453,"y":1832.4999694824219,"wires":[["b7ad516f.0ac22"]]},{"id":"37ddcac7.ca8756","type":"inject","z":"512e2cc3.3a1bdc","name":"fH","topic":"dat/fH","payload":"17","payloadType":"num","repeat":"85","crontab":"","once":true,"onceDelay":0.1,"x":188.00000762939453,"y":1872.4999694824219,"wires":[["84602ba7.9c836"]]},{"id":"8c6eb531.62e408","type":"change","z":"512e2cc3.3a1bdc","name":"phex2","rules":[{"t":"set","p":"topic","pt":"msg","to":"phex2/dat/tH","tot":"str"},{"t":"set","p":"points","pt":"msg","to":"500","tot":"num"},{"t":"set","p":"deadband","pt":"msg","to":"0.5","tot":"num"},{"t":"set","p":"attributes","pt":"msg","to":"{\"units\":\"°C\",\"title\":\"Primary Flow Temperature\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":595.0000076293945,"y":1712.4999694824219,"wires":[["47608a0f.ed068c"]]},{"id":"efd31b57.73ca8","type":"inject","z":"512e2cc3.3a1bdc","name":"Setup Calculations","topic":"calculations","payload":"[{\"topic\":\"common/dat/fH\",\"filter\":\"+/+/+/dat/fH\",\"eval\":\"function (a, b) { return a + b; }\",\"parameters\":[\"phex1/dat/fH\",\"phex2/dat/fH\"],\"title\":\"Primary Flow Rate\",\"units\":\"lpm\",\"points\":365,\"deadband\":1}]","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":"0","x":279,"y":1182,"wires":[["25da332b.be35fc"]]},{"id":"25da332b.be35fc","type":"heatwebCalc","z":"512e2cc3.3a1bdc","name":"","x":418,"y":1239,"wires":[["26de6b3f.6399fc"]]},{"id":"a7f56b83.82839","type":"link out","z":"512e2cc3.3a1bdc","name":"","links":["22b79bdf.56f684"],"x":933.8571090698242,"y":2654.2143869400024,"wires":[]},{"id":"494d5b51.639b94","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"set/location","payload":"R&D Garden Shed","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":226.85713958740234,"y":2654.2142629623413,"wires":[["66b50bff.1a685c"]]},{"id":"66b50bff.1a685c","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"points","pt":"msg","to":"1","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":758.8571243286133,"y":2653.214324951172,"wires":[["a7f56b83.82839"]]},{"id":"7858b967.4140c","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"common/set/tSet","payload":"70","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":268.85711669921875,"y":2738.21435546875,"wires":[["9efda712.cb2688"]]},{"id":"e9a6272.1196ad8","type":"comment","z":"512e2cc3.3a1bdc","name":"Persistent data (kept between reboots) is stored in global.settings, and global.deviceSettings for devices. These are set using the data group /set/ in the topic. ","info":"","x":589.8571395874023,"y":2514.2142629623413,"wires":[]},{"id":"7884d1d6.0d522","type":"comment","z":"512e2cc3.3a1bdc","name":"Saved settings are represented in a topic using the /settings/ data group. e.g.. /set/runMode, is replaced by /settings/runMode output and is saved in global.settings.","info":"","x":609.8571395874023,"y":2543.2142629623413,"wires":[]},{"id":"19b04548.dde06b","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"phex1/set/runMode","payload":"auto","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":246.85712432861328,"y":2696.214324951172,"wires":[["66b50bff.1a685c"]]},{"id":"4902c215.b56004","type":"comment","z":"512e2cc3.3a1bdc","name":" e.g.. phex1/set/runMode, is replaced by phex1/settings/runMode output and is saved in global.deviceSettings under the device id.","info":"","x":499.85713958740234,"y":2573.2142629623413,"wires":[]},{"id":"a0210254.69228","type":"comment","z":"512e2cc3.3a1bdc","name":"RANDOM DATA","info":"","x":181.00000762939453,"y":1655.4999694824219,"wires":[]},{"id":"258ed5d3.10073a","type":"change","z":"512e2cc3.3a1bdc","name":"common tH with alarms","rules":[{"t":"set","p":"topic","pt":"msg","to":"common/dat/tH","tot":"str"},{"t":"set","p":"points","pt":"msg","to":"500","tot":"num"},{"t":"set","p":"deadband","pt":"msg","to":"0.5","tot":"num"},{"t":"set","p":"attributes","pt":"msg","to":"{\"units\":\"°C\",\"title\":\"Primary Flow Temperature\"}","tot":"json"},{"t":"set","p":"alarms","pt":"msg","to":"[{\"topic\":\"alarm/tH\",\"evalOn\":\"function (a,b,c) { return (parseInt(b)==1 || parseInt(c)==1); }\",\"eval\":\"function (a,b,c,d) { return a < ((d||70)+3); }\",\"parameters\":[\"dat/tH\",\"phex1/dat/run\",\"phex2/dat/run\",\"common/settings/tSet\"],\"minutesOn\":1,\"description\":\"Warning, supply temperature\",\"minutesRepeat\":120},{\"topic\":\"alarm/tH\",\"evalOn\":\"function (a,b,c) { return (parseInt(b)==1 || parseInt(c)==1); }\",\"eval\":\"function (a,b,c,d) { return a < (d||70); }\",\"parameters\":[\"dat/tH\",\"phex1/dat/run\",\"phex2/dat/run\",\"common/settings/tSet\"],\"minutesOn\":1,\"description\":\"Low supply temperature\",\"minutesRepeat\":60},{\"topic\":\"alarm/tH\",\"eval\":\"function (a) { return a > 92; }\",\"parameters\":[\"dat/tH\"],\"minutesOn\":1,\"description\":\"DANGER, High supply temperature\",\"minutesRepeat\":15}]","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":654.0000076293945,"y":1636.4999694824219,"wires":[["47608a0f.ed068c"]]},{"id":"c747165e.9579b8","type":"inject","z":"512e2cc3.3a1bdc","name":"too hot","topic":"tH","payload":"100","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":375.00000762939453,"y":1590.4999694824219,"wires":[["258ed5d3.10073a"]]},{"id":"552934ed.612564","type":"inject","z":"512e2cc3.3a1bdc","name":"on","topic":"dat/run","payload":"1","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":708.0000076293945,"y":2345.499969482422,"wires":[["8b8bb4af.43c018"]]},{"id":"8b8bb4af.43c018","type":"change","z":"512e2cc3.3a1bdc","name":"phex1/dat/run","rules":[{"t":"set","p":"topic","pt":"msg","to":"phex1/dat/run","tot":"str"},{"t":"set","p":"points","pt":"msg","to":"10","tot":"num"},{"t":"set","p":"title","pt":"msg","to":"Run state","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":913.0000076293945,"y":2423.499969482422,"wires":[["63d276c2.9eddf8"]]},{"id":"bd2f2814.fcb12","type":"inject","z":"512e2cc3.3a1bdc","name":"off","topic":"dat/run","payload":"0","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":708.0000076293945,"y":2381.499969482422,"wires":[["8b8bb4af.43c018"]]},{"id":"d01f062b.b51768","type":"inject","z":"512e2cc3.3a1bdc","name":"cold","topic":"tH","payload":"72","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":375.00000762939453,"y":1626.4999694824219,"wires":[["258ed5d3.10073a"]]},{"id":"12a5f6c7.286b99","type":"comment","z":"512e2cc3.3a1bdc","name":"Device commands require handling...","info":"","x":212.00000762939453,"y":2372.499969482422,"wires":[]},{"id":"630e662.f534a18","type":"subflow:1ed419df.9ad846","z":"512e2cc3.3a1bdc","name":"","env":[],"x":708.0000076293945,"y":2422.499969482422,"wires":[["8b8bb4af.43c018"]]},{"id":"63d276c2.9eddf8","type":"link out","z":"512e2cc3.3a1bdc","name":"","links":["cca4d4f8.5f0af8"],"x":1054.0000076293945,"y":2423.499969482422,"wires":[]},{"id":"20aa6e2b.1ebf12","type":"link out","z":"512e2cc3.3a1bdc","name":"","links":["22b79bdf.56f684"],"x":444,"y":1394.5,"wires":[]},{"id":"987a89e7.66001","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"phex1/system/deviceType","payload":"plate heat exchanger","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":232,"y":1373.5,"wires":[["20aa6e2b.1ebf12"]]},{"id":"222d0f63.8942f8","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"phex2/system/deviceType","payload":"plate heat exchanger","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":235,"y":1409.5,"wires":[["20aa6e2b.1ebf12"]]},{"id":"347e70c9.ceb0f","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"common/system/deviceType","payload":"primary circuit","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":216,"y":1445.5,"wires":[["20aa6e2b.1ebf12"]]},{"id":"4691c72e.455d4","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"title\":\"Substations\",\"subtitle\":\"Plate Heat Exchange Systems for District Heatiing\",\"body\":\"We manufacture substations to any hydraulic design, fitted with the Heatweb Node-HIU control system.\",\"bannerImageLarge\":\"/files/images/1800px-Screenshot_2020-08-08_Node-RED_Dashboard.png\",\"bannerImageSmall\":\"/files/images/800px-Screenshot_2020-08-08_Node-RED_Dashboard.png\"}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":174.00000762939453,"y":2983.499969482422,"wires":[["faf256d8.46b55"]]},{"id":"84b35607.62c8e","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"sections.substations","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":2983.5,"wires":[[]]},{"id":"faf256d8.46b55","type":"template","z":"512e2cc3.3a1bdc","name":"substations","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<p>The Heatweb control platform provides a graphics engine for delivering a realtime graphical dashboard - realtime in the sense of 10s screen updates typically.  \n</p><p>The graphics are created using any standard software package capable of editing SVG image files - the web standard for vector graphics.  \n</p><p><img alt=\"Screenshot 2020-09-19 Heatweb MQTT Desk.png\" src=\"https://heatweb.co.uk/w/images/thumb/6/60/Screenshot_2020-09-19_Heatweb_MQTT_Desk.png/900px-Screenshot_2020-09-19_Heatweb_MQTT_Desk.png\" width=\"900\" height=\"368\" srcset=\"https://heatweb.co.uk/w/images/thumb/6/60/Screenshot_2020-09-19_Heatweb_MQTT_Desk.png/1350px-Screenshot_2020-09-19_Heatweb_MQTT_Desk.png 1.5x, https://heatweb.co.uk/w/images/thumb/6/60/Screenshot_2020-09-19_Heatweb_MQTT_Desk.png/1800px-Screenshot_2020-09-19_Heatweb_MQTT_Desk.png 2x\" />\n</p>","output":"str","x":353.00000762939453,"y":2983.499969482422,"wires":[["84b35607.62c8e"]]},{"id":"9efda712.cb2688","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"title","pt":"msg","to":"Setpoint temperature","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":464,"y":2738.5,"wires":[["66b50bff.1a685c"]]},{"id":"b02bd442.6a0258","type":"comment","z":"512e2cc3.3a1bdc","name":"The global.sections object stores additional pages available through the browser interface. Content can be updated using template nodes.","info":"","x":528.0000076293945,"y":2860.499969482422,"wires":[]},{"id":"a72b08d3.2e2708","type":"comment","z":"512e2cc3.3a1bdc","name":"Each section must have an id, title, and body. They can additionally have banners, with a subtitle and banner image (bannerImageSmall & bannerImageLarge)","info":"","x":598.0000076293945,"y":2890.499969482422,"wires":[]},{"id":"ec3cd80c.f4345","type":"mqtt in","z":"512e2cc3.3a1bdc","name":"TestNode1/cmd/ngrok","topic":"testingRemoteConnection/+/TestNode1/cmd/ngrok","qos":"0","datatype":"auto","broker":"5fa73555.16541c","x":164,"y":287,"wires":[["d8fdaf9a.60e6e8"]]},{"id":"2dd27ad8.f189fe","type":"debug","z":"512e2cc3.3a1bdc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":609,"y":288,"wires":[]},{"id":"d8fdaf9a.60e6e8","type":"function","z":"512e2cc3.3a1bdc","name":"","func":"\nif (msg.payload.substr(0,5)!==\"port:\") {\n    return null;\n}\nmsg.topic = \"port\";\nmsg.payload = msg.payload.substr(5);\n\nreturn msg;","outputs":1,"noerr":0,"x":430,"y":288,"wires":[["2dd27ad8.f189fe","f275f537.89c3b"]]},{"id":"7b2d996f.42f018","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"default\":{\"title\":\"General Operation\",\"show\":\"common.dat.tH,common.stat.vwatH24,common.dat.fH\"},\"phex1\":{\"title\":\"Plate Heat Exchanger 1\",\"show\":\"phex1.dat.tH,phex1.dat.tHo\"},\"memory\":{\"title\":\"System Memory (MB Free)\",\"show\":\"TestNode1.system.mem_free\"}}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":167,"y":3798.5,"wires":[["f0486a51.48e38"]]},{"id":"f0486a51.48e38","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"graphs","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":418,"y":3798.5,"wires":[[]]},{"id":"52bcea5a.b8e5d4","type":"comment","z":"512e2cc3.3a1bdc","name":"The global.graphs object stores graph pages available through the browser interface. ","info":"","x":363,"y":3704.5,"wires":[]},{"id":"95f93b0.8672a48","type":"comment","z":"512e2cc3.3a1bdc","name":"Each graph must have an id, title, and show fields. The show field is a comma seperated list of reading objects. E.g. local.phex1.dat.tH,local.phex1.dat.tHo","info":"","x":573,"y":3734.5,"wires":[]},{"id":"4a839f53.4545c8","type":"comment","z":"512e2cc3.3a1bdc","name":"Content can include Mustache style includes, exposing the readings object in full.  E.g.  {{local.phex1.dat.tH.value}} {{local.phex1.dat.tH.units}}","info":"","x":538.0000076293945,"y":2920.499969482422,"wires":[]},{"id":"b4821687.325258","type":"inject","z":"512e2cc3.3a1bdc","name":"on","topic":"dat/run","payload":"1","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":892.0000076293945,"y":2271.499969482422,"wires":[["6e4813eb.cf15fc"]]},{"id":"62a1e0ba.11ac2","type":"inject","z":"512e2cc3.3a1bdc","name":"off","topic":"dat/run","payload":"0","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":892.0000076293945,"y":2307.499969482422,"wires":[["6e4813eb.cf15fc"]]},{"id":"6e4813eb.cf15fc","type":"change","z":"512e2cc3.3a1bdc","name":"phex2/dat/run","rules":[{"t":"set","p":"topic","pt":"msg","to":"phex2/dat/run","tot":"str"},{"t":"set","p":"points","pt":"msg","to":"10","tot":"num"},{"t":"set","p":"title","pt":"msg","to":"Run state","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":922.0000076293945,"y":2353.499969482422,"wires":[["63d276c2.9eddf8"]]},{"id":"ab3a7306.924228","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"Summary\":{\"title\":\"Summary\",\"sections\":[\"summary\",\"devices\",\"readings\",\"substations\",\"radar\"]}}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":160,"y":3952.5,"wires":[["a8ffbe.4df0304"]]},{"id":"a8ffbe.4df0304","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"pages","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":415,"y":3951.5,"wires":[[]]},{"id":"60e2bdab.3066dc","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"title\":\"Summary\",\"body\":\"Data can be inserted into browser pages using Mustache syntax. <br>Phex1 Hot Input: {{phex1.dat.tH.value}}{{phex1.dat.tH.units}}.\"}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":172.00000762939453,"y":3030.499969482422,"wires":[["966f40a7.2af0c8"]]},{"id":"11524c02.28e3bc","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"sections.summary","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":619,"y":3030.5,"wires":[[]]},{"id":"966f40a7.2af0c8","type":"template","z":"512e2cc3.3a1bdc","name":"summary","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"plain","template":"<table class=\"table  table-striped\">\n    <thead class=\"thead-dark\"><th>Heat Exchanger</th><th>PHEx 1</th><th>Common</th><th>PHEx 2</th></thead>\n     <tr><td>State</td>\n    <td>{{local.phex1.stat.state.value}}</td>\n    <td>{{local.common.stat.state.value}}</td>\n    <td>{{local.phex2.stat.state.value}}</td>\n    \n    <tr><td>Primary In</td>\n    <td>{{local.common.dat.tH.value}}{{local.common.dat.tH.units}}</td>\n    <td>{{local.common.dat.tH.value}}{{local.common.dat.tH.units}}</td>\n    <td>{{local.common.dat.tH.value}}{{local.common.dat.tH.units}}</td>\n    </tr>\n    \n    <tr><td>Setpoint</td>\n    <td> </td>\n    <td>{{local.common.settings.tSet.value}}{{local.common.dat.tH.units}}</td>\n    <td> </td>\n    </tr>\n    \n    <tr><td>Primary Out</td>\n    <td>{{local.phex1.dat.tHo.value}}{{local.phex1.dat.tHo.units}}</td>\n    <td> </td>\n    <td>{{local.phex2.dat.tHo.value}}{{local.phex2.dat.tHo.units}}</td>\n    </tr>\n    </table>","output":"str","x":343.00000762939453,"y":3030.499969482422,"wires":[["11524c02.28e3bc"]]},{"id":"468bab2e.8fca84","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"title\":\"To Do List\",\"subtitle\":\"Features to be added.\",\"body\":\"\",\"bannerImageLarge\":\"/files/images/1800px-Screenshot_2020-08-08_Node-RED_Dashboard.png\",\"bannerImageSmall\":\"/files/images/800px-Screenshot_2020-08-08_Node-RED_Dashboard.png\"}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":174.00000762939453,"y":3080.499969482422,"wires":[["3081610b.93818e"]]},{"id":"1fe69457.66a97c","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"sections.todo","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":609,"y":3080.5,"wires":[[]]},{"id":"3081610b.93818e","type":"template","z":"512e2cc3.3a1bdc","name":"To Do List","field":"payload.body","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<ul>\n    <li>Filter for readings API</li>\n    <li>Settings pages</li>\n    <li>Proxy LAN Device node (stuck on absolutes)</li>\n    <li>Local images</li>\n    <li>File uploads</li>\n    <li>PDF Nodes</li>\n    <li>Users</li>\n    <li>Insert graphs into pages</li>\n    <li>Alarms and Documents to Recipients via email, phone or post.</li>\n    <li>MQTT client html pages:<br>- user/password prompt</li>\n    <li>Timed update alarm indicator in navigation bar.</li>\n    <li>Alerts for alarms</li>\n    <li>SVG Dashboards using MQTT socket connection</li>\n    <li>MQTT Recording & Playback</li>\n</ul>","output":"str","x":345.00000762939453,"y":3080.499969482422,"wires":[["1fe69457.66a97c"]]},{"id":"e2fd34be.d0608","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"title\":\"Hydraulic Interface Units\",\"subtitle\":\"Plate Heat Exchange Systems for individual dwellings\",\"body\":\"We manufacture the UK most efficient range of HIUs, as independently tested to BESA standards.\",\"bannerImageLarge\":\"/files/images/Heat-Interface-Unit-manufacturer.jpg\",\"bannerImageSmall\":\"/files/images/Heat-Interface-Unit-manufacturer-600x390.jpg\"}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":170.00000762939453,"y":3128.499969482422,"wires":[["1d07c1bb.fe592e"]]},{"id":"1d07c1bb.fe592e","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"sections.hius","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":607,"y":3128.5,"wires":[[]]},{"id":"e7483535.ffa4f","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"title\":\"About Heatweb\",\"subtitle\":\"Thermal Integration Ltd.\",\"body\":\"Thermal Integration Ltd. are manufacturers of hot water and central heating equipment.\",\"bannerImageLarge\":\"/files/images/district-heating-substations.jpg\",\"bannerImageSmall\":\"/files/images/district-heating-substations-600x210.jpg\"}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":172.00000762939453,"y":3173.499969482422,"wires":[["20063671.0082d2"]]},{"id":"20063671.0082d2","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"sections.aboutUs","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":617,"y":3173.5,"wires":[[]]},{"id":"d8820259.102bf","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"title\":\"Radar Charts\",\"background\":\"#cbced8\",\"fullscreen\":true}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":171.00000762939453,"y":3222.499969482422,"wires":[["e5cbbb0c.34d15"]]},{"id":"59467c1a.b77b4c","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"sections.radar","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":607,"y":3222.5,"wires":[[]]},{"id":"e5cbbb0c.34d15","type":"template","z":"512e2cc3.3a1bdc","name":"radar","field":"payload.body","fieldType":"msg","format":"html","syntax":"plain","template":"\t<script src=\"/includes/chart.js/Chart.min.js\"></script>\n\t<script src=\"/includes/chart.js/utils.js\"></script>\n\n\t<style>\n\t\tcanvas {\n\t\t\t-moz-user-select: none;\n\t\t\t-webkit-user-select: none;\n\t\t\t-ms-user-select: none;\n\t\t}\n\t</style>\n\n\n\n  <p>The Heatweb Node-HIU system comes with a variety of graphing packages.  \n      The example here shows a radar plot that can be linked to tap data, for example, showing flow rates in each property as well as delivery temperatures. \n      The transparency of the section can be linked to tap run time, becoming solid after 30 seconds. </p>\n\n\t<div id=\"canvas-holder\" style=\"width:70%\">\n\t\t<canvas id=\"chart-area\"></canvas>\n\t</div>\n\t<button id=\"randomizeData\">Randomize Data</button>\n\t<button id=\"addData\">Add Data</button>\n\t<button id=\"removeData\">Remove Data</button>\n\t<script>\n\t\tvar randomScalingFactor = function() {\n\t\t\treturn Math.round(Math.random() * 100);\n\t\t};\n\n\t\tvar chartColors = window.chartColors;\n\t\tvar color = Chart.helpers.color;\n\t\tvar config = {\n\t\t\tdata: {\n\t\t\t\tdatasets: [{\n\t\t\t\t\tdata: [\n\t\t\t\t\t\trandomScalingFactor(),\n\t\t\t\t\t\trandomScalingFactor(),\n\t\t\t\t\t\trandomScalingFactor(),\n\t\t\t\t\t\trandomScalingFactor(),\n\t\t\t\t\t\trandomScalingFactor(),\n\t\t\t\t\t],\n\t\t\t\t\tbackgroundColor: [\n\t\t\t\t\t\tcolor(chartColors.red).alpha(0.5).rgbString(),\n\t\t\t\t\t\tcolor(chartColors.orange).alpha(0.5).rgbString(),\n\t\t\t\t\t\tcolor(chartColors.yellow).alpha(0.5).rgbString(),\n\t\t\t\t\t\tcolor(chartColors.green).alpha(0.5).rgbString(),\n\t\t\t\t\t\tcolor(chartColors.blue).alpha(0.5).rgbString(),\n\t\t\t\t\t],\n\t\t\t\t\tlabel: 'My dataset' // for legend\n\t\t\t\t}],\n\t\t\t\tlabels: [\n\t\t\t\t\t'Red',\n\t\t\t\t\t'Orange',\n\t\t\t\t\t'Yellow',\n\t\t\t\t\t'Green',\n\t\t\t\t\t'Blue'\n\t\t\t\t]\n\t\t\t},\n\t\t\toptions: {\n\t\t\t\tresponsive: true,\n\t\t\t\tlegend: {\n\t\t\t\t\tposition: 'right',\n\t\t\t\t},\n\t\t\t\ttitle: {\n\t\t\t\t\tdisplay: true,\n\t\t\t\t\ttext: 'Chart.js Polar Area Chart'\n\t\t\t\t},\n\t\t\t\tscale: {\n\t\t\t\t\tticks: {\n\t\t\t\t\t\tbeginAtZero: true\n\t\t\t\t\t},\n\t\t\t\t\treverse: false\n\t\t\t\t},\n\t\t\t\tanimation: {\n\t\t\t\t\tanimateRotate: false,\n\t\t\t\t\tanimateScale: true\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\twindow.onload = function() {\n\t\t\tvar ctx = document.getElementById('chart-area');\n\t\t\twindow.myPolarArea = Chart.PolarArea(ctx, config);\n\t\t};\n\n\t\tdocument.getElementById('randomizeData').addEventListener('click', function() {\n\t\t\tconfig.data.datasets.forEach(function(piece, i) {\n\t\t\t\tpiece.data.forEach(function(value, j) {\n\t\t\t\t\tconfig.data.datasets[i].data[j] = randomScalingFactor();\n\t\t\t\t});\n\t\t\t});\n\t\t\twindow.myPolarArea.update();\n\t\t});\n\n\t\tvar colorNames = Object.keys(window.chartColors);\n\t\tdocument.getElementById('addData').addEventListener('click', function() {\n\t\t\tif (config.data.datasets.length > 0) {\n\t\t\t\tconfig.data.labels.push('data #' + config.data.labels.length);\n\t\t\t\tconfig.data.datasets.forEach(function(dataset) {\n\t\t\t\t\tvar colorName = colorNames[config.data.labels.length % colorNames.length];\n\t\t\t\t\tdataset.backgroundColor.push(window.chartColors[colorName]);\n\t\t\t\t\tdataset.data.push(randomScalingFactor());\n\t\t\t\t});\n\t\t\t\twindow.myPolarArea.update();\n\t\t\t}\n\t\t});\n\t\tdocument.getElementById('removeData').addEventListener('click', function() {\n\t\t\tconfig.data.labels.pop(); // remove the label first\n\t\t\tconfig.data.datasets.forEach(function(dataset) {\n\t\t\t\tdataset.backgroundColor.pop();\n\t\t\t\tdataset.data.pop();\n\t\t\t});\n\t\t\twindow.myPolarArea.update();\n\t\t});\n\t</script>\n<br> <br> ","output":"str","x":330.00000762939453,"y":3222.499969482422,"wires":[["59467c1a.b77b4c"]]},{"id":"3ece12ce.3f352e","type":"inject","z":"512e2cc3.3a1bdc","name":"too cold","topic":"tH","payload":"65","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":374.00000762939453,"y":1662.4999694824219,"wires":[["258ed5d3.10073a"]]},{"id":"ab92ece8.a5748","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"title\":\"Raspberry Pi 4\",\"subtitle\":\"The 3rd best selling computer platform of all time.\",\"body\":\"\",\"bannerImageLarge\":\"https://www.raspberrypi.org/homepage-9df4b/static/raspberry-pi-4-labelled@2x-c1a040c7511610e7274e388432a458c4.png\",\"bannerImageSmall\":\"https://www.raspberrypi.org/homepage-9df4b/static/raspberry-pi-4-labelled@2x-c1a040c7511610e7274e388432a458c4.png\"}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":168.00000762939453,"y":3277.499969482422,"wires":[["3c6d8c0e.31e504"]]},{"id":"70e490ee.f9ea78","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"sections.rpi","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":598,"y":3277.5,"wires":[[]]},{"id":"3c6d8c0e.31e504","type":"template","z":"512e2cc3.3a1bdc","name":"Pi","field":"payload.body","fieldType":"msg","format":"html","syntax":"plain","template":"<div class=\"row\">\n  <div class=\"col-sm-6\"><img src=\"https://www.raspberrypi.org/homepage-9df4b/static/raspberry-pi-4-labelled@2x-c1a040c7511610e7274e388432a458c4.png\" width=\"100%\"></div>\n  <div class=\"col-sm-6\">\n      \n      \n<ul>\n\n    <li>Broadcom BCM2711, Quad core Cortex-A72 (ARM v8) 64-bit SoC @ 1.5GHz</li>\n    <li>2GB, 4GB or 8GB LPDDR4-3200 SDRAM (depending on model)</li>\n    <li>2.4 GHz and 5.0 GHz IEEE 802.11ac wireless, Bluetooth 5.0, BLE</li>\n    <li>Gigabit Ethernet</li>\n    <li>2 USB 3.0 ports; 2 USB 2.0 ports.</li>\n    <li>Raspberry Pi standard 40 pin GPIO header (fully backwards compatible with previous boards)</li>\n    <li>2 × micro-HDMI ports (up to 4kp60 supported)</li>\n    <li>2-lane MIPI DSI display port</li>\n    <li>2-lane MIPI CSI camera port</li>\n    <li>4-pole stereo audio and composite video port</li>\n    <li>H.265 (4kp60 decode), H264 (1080p60 decode, 1080p30 encode)</li>\n    <li>OpenGL ES 3.0 graphics</li>\n    <li>Micro-SD card slot for loading operating system and data storage</li>\n    <li>5V DC via USB-C connector (minimum 3A*)</li>\n    <li>5V DC via GPIO header (minimum 3A*)</li>\n    <li>Power over Ethernet (PoE) enabled (requires separate PoE HAT)</li>\n    <li>Operating temperature: 0 – 50 degrees C ambient</li>\n</ul>\n    \n      \n      \n  </div>\n</div>\n\n","output":"str","x":327.00000762939453,"y":3277.499969482422,"wires":[["70e490ee.f9ea78"]]},{"id":"7922a6e4.0be028","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"title\":\"Brainbox BB-400\",\"subtitle\":\"Industrial Edge Computing and I/O\",\"body\":\"\",\"bannerImageLarge\":\"http://st2.staticbb.com/files/pages/products/controller/jumbotron-1.png.pagespeed.ce.UTQSsfUCRq.png\",\"bannerImageSmall\":\"http://st2.staticbb.com/files/pages/products/controller/jumbotron-1.png.pagespeed.ce.UTQSsfUCRq.png\"}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":169.00000762939453,"y":3321.499969482422,"wires":[["baea760e.438ce"]]},{"id":"c54ec600.7780f","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"sections.bb400","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":607,"y":3321.5,"wires":[[]]},{"id":"baea760e.438ce","type":"template","z":"512e2cc3.3a1bdc","name":"BB","field":"payload.body","fieldType":"msg","format":"html","syntax":"plain","template":"","output":"str","x":328.00000762939453,"y":3321.499969482422,"wires":[["c54ec600.7780f"]]},{"id":"56deab4.db87354","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"title\":\"Live DHW Data\",\"subtitle\":\"Real-time tap flow rates at one second resolution.\",\"body\":\"\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":165,"y":3457.5,"wires":[["20f1a32.96692dc"]]},{"id":"b1b85bd8.718be8","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"sections.livedhw","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":744,"y":3455.5,"wires":[[]]},{"id":"20f1a32.96692dc","type":"template","z":"512e2cc3.3a1bdc","name":"Live DHW Polar","field":"payload.body","fieldType":"msg","format":"html","syntax":"plain","template":"\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js\" type=\"text/javascript\"></script>\n\n<script>\nvar readings = {};\n</script>\n\n<style>\n\n.tt {\n  font-family: Arial, Helvetica, sans-serif;\n  font-size: 24px;\n  border-collapse: collapse;\n  width: 100%;\n}\n\n.tt td, #customers th {\n  border: 1px solid #ddd;\n  padding: 5px 25px 5px 5px;\n}\n\n.tt tr:nth-child(even){background-color: #f2f2f2;}\n\n.tt tr:hover {background-color: #ddd;}\n\n.tt th {\n  padding: 5px;\n  text-align: left;\n  background-color: #303c43;;\n  color: white;\n}\n</style>\n\n\n</head>\n<body>\n<script type=\"text/javascript\">\n\nvar a = new Date();\n \t\t\n// Create a client instance\n//client = new Paho.MQTT.Client(\"hw3.ddns.net\", Number(8083), \"cl\"+a.getTime());\nclient = new Paho.MQTT.Client(\"broker.hivemq.com\", Number(8000), \"cl\"+a.getTime());\n\n// set callback handlers\nclient.onConnectionLost = onConnectionLost;\nclient.onMessageArrived = onMessageArrived;\n\n///client.username_pw_set(username=\"oop7zooR\",password=\"oop7zooRoop7zooR\")\n// now can connect\n\n// connect the client\n///client.connect({onSuccess:onConnect, useSSL:true});\n\n// Connect the client, with a Username and Password\n//client.connect({onSuccess:onConnect, userName:'oop7zooR', password:'oop7zooRoop7zooR', useSSL:true});\nclient.connect({onSuccess:onConnect, useSSL:false});\n\n// called when the client connects\nfunction onConnect() {\n  // Once a connection has been made, make a subscription and send a message.\n  console.log(\"onConnect\");\n  client.subscribe(\"hw/diversitydemo/+/+/fC\"); // hw/diversitydemo/+/+/fC    //  ihiu/oop7zooR/#\n  message = new Paho.MQTT.Message(\"1\");\n  message.destinationName = \"hw/diversitydemo/start\";   //  ihiu/oop7zooR/oop7zooR/test/test\n  client.send(message);\n}\n\n// called when the client loses its connection\nfunction onConnectionLost(responseObject) {\n  if (responseObject.errorCode !== 0) {\n    console.log(\"onConnectionLost:\"+responseObject.errorMessage);\n}\n}\n\n// called when a message arrives\nfunction onMessageArrived(message) {\n  console.log(\"onMessageArrived:\"+message.payloadString);\n  \n  //document.getElementById(\"mqlist\").innerHTML = mql + message.destinationName + \": \" + message.payloadString + \"<br>\";\n\n  \n  if(!readings[message.destinationName]) {  // if new system add to plot\n\n\n    if (config.data.datasets.length > 0) {\n            config.data.labels.push('HIU' + (config.data.labels.length + 1));\n            config.data.datasets.forEach(function(dataset) {\n                var colorName = colorNames[config.data.labels.length % colorNames.length];\n                dataset.backgroundColor.push(window.chartColors[colorName]);\n                dataset.data.push(parseFloat(message.payloadString));\n            });\n            window.myPolarArea.update();\n        }\n\n        readings[message.destinationName] = { \"topic\":message.destinationName, \"payload\":message.payloadString, \"id\": config.data.labels.length - 1};\n        \n  } else {\n\n        readings[message.destinationName].payload = message.payloadString ;\n  \n\n  }\n\n  readings[message.destinationName].payload = parseFloat(readings[message.destinationName].payload);\n  if (readings[message.destinationName].payload < 0.1) { readings[message.destinationName].payload = 0;}\n  //config.data.datasets[i].data[j] = randomScalingFactor();\n\n  config.data.datasets[0].data[readings[message.destinationName][\"id\"]] = parseFloat(readings[message.destinationName][\"payload\"]);\n  //config.data.labels[readings[message.destinationName][\"id\"]] = \"HIU\" +readings[message.destinationName][\"id\"] + \": \" + parseFloat(readings[message.destinationName][\"payload\"]);\n  window.myPolarArea.update();\n\n\n  \n//   var sortable = [];\n// \tfor (var mqt in readings) {\n// \t\tsortable.push([mqt]);\n// \t}\n\n// \tsortable.sort(function(a, b) {\n// \t\treturn a[0] > b[0];\n// \t});\n  \n  \n  \n// \tvar mql = '<table class=\"tt\"><tr><th align=\"left\">Topic</th><th>Data</th></tr>';\n\t\n// \tfor (var kk in sortable) {\n// \t\tvar k = sortable[kk][0];\n// \t\tmql += \"<tr><td>\" + k.replace(/\\//g,\" / \") + \"</td><td>\" + readings[k].payload + \"</td></tr>\";\n// \t}\n// \tmql += \"</table>\";\n\t\n\t\n// \tdocument.getElementById(\"mqlist\").innerHTML = mql;\n  \n}\n\n\n\n\n</script>\n\n\n\n<script src=\"/includes/chart.js/Chart.min.js\"></script>\n<script src=\"/includes/chart.js/utils.js\"></script>\n\n<style>\n    canvas {\n        -moz-user-select: none;\n        -webkit-user-select: none;\n        -ms-user-select: none;\n    }\n</style>\n\n\n<!-- <section style=\"height: 100vh; background: #cbced8\"> -->\n\n<!-- <p>This page recieves real-time tap use data, showing flow rates in each property as well as delivery temperatures.  -->\n\n<div id=\"canvas-holder\" style=\"width:80%;\">\n    <canvas id=\"chart-area\"></canvas>\n</div>\n<!-- <button id=\"randomizeData\">Randomize Data</button>\n<button id=\"addData\">Add Data</button>\n<button id=\"removeData\">Remove Data</button> -->\n<script>\n    var randomScalingFactor = function() {\n        return Math.round(Math.random() * 100);\n    };\n\n    var chartColors = window.chartColors;\n    var color = Chart.helpers.color;\n    var config = {\n        data: {\n            datasets: [{\n                data: [],\n                backgroundColor: [],\n                label: 'My dataset' // for legend\n            }],\n            labels: []\n        },\n        options: {\n            responsive: true,\n            legend: {\n                position: 'left',\n            },\n            title: {\n                display: false,\n                text: 'Live DHW Data'\n            },\n            scale: {\n                ticks: {\n                    beginAtZero: true\n                },\n                reverse: false,\n            },\n            animation: {\n                animateRotate: true,\n                animateScale: false\n            }\n        }\n    };\n\n    window.onload = function() {\n        var ctx = document.getElementById('chart-area');\n        window.myPolarArea = Chart.PolarArea(ctx, config);\n    };\n\n    // document.getElementById('randomizeData').addEventListener('click', function() {\n    //     config.data.datasets.forEach(function(piece, i) {\n    //         piece.data.forEach(function(value, j) {\n    //             config.data.datasets[i].data[j] = randomScalingFactor();\n    //         });\n    //     });\n    //     window.myPolarArea.update();\n    // });\n\n    var colorNames = Object.keys(window.chartColors);\n    // document.getElementById('addData').addEventListener('click', function() {\n    //     if (config.data.datasets.length > 0) {\n    //         config.data.labels.push('data #' + config.data.labels.length);\n    //         config.data.datasets.forEach(function(dataset) {\n    //             var colorName = colorNames[config.data.labels.length % colorNames.length];\n    //             dataset.backgroundColor.push(window.chartColors[colorName]);\n    //             dataset.data.push(randomScalingFactor());\n    //         });\n    //         window.myPolarArea.update();\n    //     }\n    // });\n    // document.getElementById('removeData').addEventListener('click', function() {\n    //     config.data.labels.pop(); // remove the label first\n    //     config.data.datasets.forEach(function(dataset) {\n    //         dataset.backgroundColor.pop();\n    //         dataset.data.pop();\n    //     });\n    //     window.myPolarArea.update();\n    // });\n</script>\n\n<!--<div id=\"mqlist\">-->\n<!-- Waiting for data... -->\n<!--</div>-->\n\n</body>\n\n</html>","output":"str","x":354,"y":3457.5,"wires":[["b1b85bd8.718be8"]]},{"id":"47608a0f.ed068c","type":"trigger","z":"512e2cc3.3a1bdc","op1":"","op2":"0","op1type":"pay","op2type":"str","duration":"-10","extend":false,"units":"s","reset":"","bytopic":"topic","name":"","x":863.0000076293945,"y":1712.4999694824219,"wires":[["6108b7a6.0a696"]]},{"id":"a63185bb.8b3828","type":"comment","z":"512e2cc3.3a1bdc","name":"Standard device topics, such as deviceType can be initialised at startup.","info":"","x":327,"y":1313,"wires":[]},{"id":"d83d294e.7d808","type":"comment","z":"512e2cc3.3a1bdc","name":"Active pages can be created using an MQTT client library to subscribe to system data.  Requires an MQTT server, and access..","info":"","x":496,"y":3390,"wires":[]},{"id":"611bfe2a.4a21a","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"title\":\"Live DHW Data (bars)\",\"subtitle\":\"Real-time tap flow rates at one second resolution.\",\"body\":\"\"}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":160,"y":3581,"wires":[["ab8ddc31.58755"]]},{"id":"57f10b02.31baa4","type":"change","z":"512e2cc3.3a1bdc","name":"","rules":[{"t":"set","p":"sections.livedhwbars","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":619,"y":3581,"wires":[[]]},{"id":"ab8ddc31.58755","type":"template","z":"512e2cc3.3a1bdc","name":"Live DHW Bar","field":"payload.body","fieldType":"msg","format":"html","syntax":"plain","template":"\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js\" type=\"text/javascript\"></script>\n\n<script>\nvar readings = {};\n</script>\n\n<style>\n\n.tt {\n  font-family: Arial, Helvetica, sans-serif;\n  font-size: 24px;\n  border-collapse: collapse;\n  width: 100%;\n}\n\n.tt td, #customers th {\n  border: 1px solid #ddd;\n  padding: 5px 25px 5px 5px;\n}\n\n.tt tr:nth-child(even){background-color: #f2f2f2;}\n\n.tt tr:hover {background-color: #ddd;}\n\n.tt th {\n  padding: 5px;\n  text-align: left;\n  background-color: #303c43;;\n  color: white;\n}\n</style>\n\n\n</head>\n<body>\n<script type=\"text/javascript\">\n\nvar a = new Date();\n \t\t\n// Create a client instance\n//client = new Paho.MQTT.Client(\"hw3.ddns.net\", Number(8083), \"cl\"+a.getTime());\nclient = new Paho.MQTT.Client(\"broker.hivemq.com\", Number(8000), \"cl\"+a.getTime());\n\n// set callback handlers\nclient.onConnectionLost = onConnectionLost;\nclient.onMessageArrived = onMessageArrived;\n\n///client.username_pw_set(username=\"oop7zooR\",password=\"oop7zooRoop7zooR\")\n// now can connect\n\n// connect the client\n///client.connect({onSuccess:onConnect, useSSL:true});\n\n// Connect the client, with a Username and Password\n//client.connect({onSuccess:onConnect, userName:'oop7zooR', password:'oop7zooRoop7zooR', useSSL:true});\nclient.connect({onSuccess:onConnect, useSSL:false});\n\n// called when the client connects\nfunction onConnect() {\n  // Once a connection has been made, make a subscription and send a message.\n  console.log(\"onConnect\");\n  client.subscribe(\"hw/diversitydemo/+/+/fC\"); // hw/diversitydemo/+/+/fC    //  ihiu/oop7zooR/#\n  message = new Paho.MQTT.Message(\"1\");\n  message.destinationName = \"hw/diversitydemo/start\";   //  ihiu/oop7zooR/oop7zooR/test/test\n  client.send(message);\n}\n\n// called when the client loses its connection\nfunction onConnectionLost(responseObject) {\n  if (responseObject.errorCode !== 0) {\n    console.log(\"onConnectionLost:\"+responseObject.errorMessage);\n}\n}\n\n// called when a message arrives\nfunction onMessageArrived(message) {\n  console.log(\"onMessageArrived:\"+message.payloadString);\n  \n  //document.getElementById(\"mqlist\").innerHTML = mql + message.destinationName + \": \" + message.payloadString + \"<br>\";\n\n  \n  if(!readings[message.destinationName]) {  // if new system add to plot\n\n\n    if (config.data.datasets.length > 0) {\n            config.data.labels.push('HIU' + (config.data.labels.length + 1));\n            config.data.datasets.forEach(function(dataset) {\n                var colorName = colorNames[config.data.labels.length % colorNames.length];\n                dataset.backgroundColor.push(window.chartColors[colorName]);\n                dataset.data.push(parseFloat(message.payloadString));\n            });\n            window.myPolarArea.update();\n        }\n\n        readings[message.destinationName] = { \"topic\":message.destinationName, \"payload\":message.payloadString, \"id\": config.data.labels.length - 1};\n        \n  } else {\n\n        readings[message.destinationName].payload = message.payloadString ;\n  \n\n  }\n\n  readings[message.destinationName].payload = parseFloat(readings[message.destinationName].payload);\n  if (readings[message.destinationName].payload < 0.1) { readings[message.destinationName].payload = 0;}\n  //config.data.datasets[i].data[j] = randomScalingFactor();\n\n  config.data.datasets[0].data[readings[message.destinationName][\"id\"]] = parseFloat(readings[message.destinationName][\"payload\"]);\n  //config.data.labels[readings[message.destinationName][\"id\"]] = \"HIU\" +readings[message.destinationName][\"id\"] + \": \" + parseFloat(readings[message.destinationName][\"payload\"]);\n  window.myPolarArea.update();\n\n\n  \n//   var sortable = [];\n// \tfor (var mqt in readings) {\n// \t\tsortable.push([mqt]);\n// \t}\n\n// \tsortable.sort(function(a, b) {\n// \t\treturn a[0] > b[0];\n// \t});\n  \n  \n  \n// \tvar mql = '<table class=\"tt\"><tr><th align=\"left\">Topic</th><th>Data</th></tr>';\n\t\n// \tfor (var kk in sortable) {\n// \t\tvar k = sortable[kk][0];\n// \t\tmql += \"<tr><td>\" + k.replace(/\\//g,\" / \") + \"</td><td>\" + readings[k].payload + \"</td></tr>\";\n// \t}\n// \tmql += \"</table>\";\n\t\n\t\n// \tdocument.getElementById(\"mqlist\").innerHTML = mql;\n  \n}\n\n\n\n\n</script>\n\n\n\n<script src=\"/includes/chart.js/Chart.min.js\"></script>\n<script src=\"/includes/chart.js/utils.js\"></script>\n\n<style>\n    canvas {\n        -moz-user-select: none;\n        -webkit-user-select: none;\n        -ms-user-select: none;\n    }\n</style>\n\n\n<!-- <section style=\"height: 100vh; background: #cbced8\"> -->\n\n<!-- <p>This page recieves real-time tap use data, showing flow rates in each property as well as delivery temperatures.  -->\n\n<div id=\"canvas-holder\" style=\"width:80%;\">\n    <canvas id=\"chart-area\"></canvas>\n</div>\n<!-- <button id=\"randomizeData\">Randomize Data</button>\n<button id=\"addData\">Add Data</button>\n<button id=\"removeData\">Remove Data</button> -->\n<script>\n    var randomScalingFactor = function() {\n        return Math.round(Math.random() * 100);\n    };\n\n    var chartColors = window.chartColors;\n    var color = Chart.helpers.color;\n\n    //new Chart(document.getElementById(\"chart-area\"), \n    \n     \n    var config= {\n        type: 'bar',\n        data: {\n          labels: [],\n          datasets: [\n            {\n              label: \"\",\n              backgroundColor: [],\n              data: []\n            }\n          ]\n        },\n        options: {\n          legend: { display: false },\n          title: {\n            display: false,\n            text: ''\n          }\n        }\n    }\n    //);\n\n    var colorNames = Object.keys(window.chartColors);\n    \n   window.onload = function() {\n        var ctx = document.getElementById('chart-area');\n        window.myPolarArea = new Chart(ctx, config);\n    };\n</script>\n\n<!--<div id=\"mqlist\">-->\n<!-- Waiting for data... -->\n<!--</div>-->\n\n</body>\n\n</html>","output":"str","x":349,"y":3581,"wires":[["57f10b02.31baa4"]]},{"id":"3c6c33eb.c5b7ec","type":"inject","z":"512e2cc3.3a1bdc","name":"","topic":"","payload":"{\"title\":\"Live DHW Data\",\"subtitle\":\"Real-time tap flow rates at one second resolution.\",\"body\":\"\"}","payloadType":"json","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":164,"y":3507,"wires":[["60cdbbd6.9fa70c"]]},{"id":"60cdbbd6.9fa70c","type":"template","z":"512e2cc3.3a1bdc","name":"Live DHW Polar + Temp","field":"payload.body","fieldType":"msg","format":"html","syntax":"plain","template":"\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js\" type=\"text/javascript\"></script>\n\n<script>\nvar readings = {};\n</script>\n\n<style>\n\n.tt {\n  font-family: Arial, Helvetica, sans-serif;\n  font-size: 24px;\n  border-collapse: collapse;\n  width: 100%;\n}\n\n.tt td, #customers th {\n  border: 1px solid #ddd;\n  padding: 5px 25px 5px 5px;\n}\n\n.tt tr:nth-child(even){background-color: #f2f2f2;}\n\n.tt tr:hover {background-color: #ddd;}\n\n.tt th {\n  padding: 5px;\n  text-align: left;\n  background-color: #303c43;;\n  color: white;\n}\n</style>\n\n\n</head>\n<body>\n<script type=\"text/javascript\">\n\nvar a = new Date();\n \t\t\n// Create a client instance\n//client = new Paho.MQTT.Client(\"hw3.ddns.net\", Number(8083), \"cl\"+a.getTime());\nclient = new Paho.MQTT.Client(\"broker.hivemq.com\", Number(8000), \"cl\"+a.getTime());\n\n// set callback handlers\nclient.onConnectionLost = onConnectionLost;\nclient.onMessageArrived = onMessageArrived;\n\n///client.username_pw_set(username=\"oop7zooR\",password=\"oop7zooRoop7zooR\")\n// now can connect\n\n// connect the client\n///client.connect({onSuccess:onConnect, useSSL:true});\n\n// Connect the client, with a Username and Password\n//client.connect({onSuccess:onConnect, userName:'oop7zooR', password:'oop7zooRoop7zooR', useSSL:true});\nclient.connect({onSuccess:onConnect, useSSL:false});\n\n// called when the client connects\nfunction onConnect() {\n  // Once a connection has been made, make a subscription and send a message.\n  console.log(\"onConnect\");\n  client.subscribe(\"hw/diversitydemo/#\"); // hw/diversitydemo/+/+/fC    //  ihiu/oop7zooR/#\n  \n  message = new Paho.MQTT.Message(\"1\");\n  message.destinationName = \"hw/diversitydemo/start\";   //  ihiu/oop7zooR/oop7zooR/test/test\n  client.send(message);\n}\n\n// called when the client loses its connection\nfunction onConnectionLost(responseObject) {\n  if (responseObject.errorCode !== 0) {\n    console.log(\"onConnectionLost:\"+responseObject.errorMessage);\n}\n}\n\n\nvar peakTot = 0;\nvar peakTotNo = 0;\nvar peakInd = 0;\n\n// called when a message arrives\nfunction onMessageArrived(message) {\n  console.log(\"onMessageArrived:\"+message.payloadString);\n  \n  //document.getElementById(\"mqlist\").innerHTML = mql + message.destinationName + \": \" + message.payloadString + \"<br>\";\n\n\n  \n  \n  var ttt = new Date().getTime();\n  \n  var devid = message.destinationName.split(\"/\")[2];\n  var dkey = message.destinationName.split(\"/\")[4];\n  \n  if(!readings[devid]) {  // if new system add to plot\n\n    if (dkey!==\"fC\") { return null; }\n    if (parseFloat(message.payloadString)<0.2) { return null; }  // dont add zero flow units\n\n    if (config.data.datasets.length > 0) {\n            config.data.labels.push('HIU' + (config.data.labels.length + 1));\n            config.data.datasets.forEach(function(dataset) {\n                //var colorName = colorNames[config.data.labels.length % colorNames.length];\n                dataset.backgroundColor.push(\"rgb(166, 166, 166, 0.5)\");\n                dataset.data.push(parseFloat(message.payloadString));\n            });\n            //window.myPolarArea.update();\n        }\n\n        readings[devid] = { \"id\": config.data.labels.length - 1, \"timestamp\":ttt};\n        \n  } \n  \n\n\n    \n    if (dkey==\"fC\") { \n        \n        readings[devid][\"payload\"] = parseFloat(message.payloadString) ; \n        if (readings[devid].payload < 0.1) {\n            \n            readings[devid].payload = 0;  \n            readings[devid].timestamp = null;\n            \n            \n        } else if (!readings[devid].timestamp) { readings[devid].timestamp = ttt; }\n        \n        config.data.datasets[0].data[readings[devid][\"id\"]] = readings[devid][\"payload\"];\n        \n        \n        \n    }\n    else if (dkey==\"tCo\") { \n        \n         readings[devid][\"temp\"] = parseFloat(message.payloadString) ; \n     \n    } else { return null; }\n    \n    \n    if (readings[devid][\"payload\"]>0.2) { // update colour when there is flow\n        \n        var runtime = (ttt - (readings[devid][\"timestamp\"]||0))/1000;\n        var alpha = 1;\n        if (runtime<20) { alpha = runtime/40; }\n        if (alpha<0.1) { alpha = 0.1; }\n        alpha = parseInt(100 * alpha) / 100;\n        \n    } else {\n        \n        alpha = 0.1;\n    }\n    \n      // rgb(166, 166, 166) \n      // rgb(77, 166, 255)\n      // rgb(102, 255, 255)\n      // rgb(102, 255, 179)\n      // rgb(255, 204, 102)\n      // rgb(255, 153, 153)\n  \n       \n        \n        var mycol = \"rgb(166, 166, 166,\" + alpha + \")\";\n        if (readings[devid][\"temp\"]<1) { mycol = \"rgb(166, 166, 166,\" + alpha + \")\"; }\n        else if (readings[devid][\"temp\"]<20) { mycol = \"rgb(77, 166, 255,\" + alpha + \")\"; }\n        else if (readings[devid][\"temp\"]<30) { mycol = \"rgb(102, 255, 255,\" + alpha + \")\"; }\n        else if (readings[devid][\"temp\"]<38) { mycol = \"rgb(102, 255, 179,\" + alpha + \")\"; }\n        else if (readings[devid][\"temp\"]<45) { mycol = \"rgb(255, 204, 102,\" + 1 + \")\"; }\n        else  { mycol = \"rgb(255, 153, 153,\" + 1 + \")\"; }\n        \n        // if (readings[devid][\"temp\"]<1) { mycol = \"#aaaaaa\"; }\n        // else if (readings[devid][\"temp\"]<20) { mycol = \"#33adff\"; }\n        // else if (readings[devid][\"temp\"]<30) { mycol = \"#33ffff\"; }\n        // else if (readings[devid][\"temp\"]<38) { mycol = \"#4dffa6\"; }\n        // else if (readings[devid][\"temp\"]<45) { mycol = \"#ffa64d\"; }\n        // else  { mycol = \"#ff8080\"; }\n        \n        \n        config.data.datasets[0].backgroundColor[readings[devid][\"id\"]] = mycol;\n        \n    \n   \n    \n  \n\n \n\n // readings[devid].payload = parseFloat(readings[devid].payload);\n  \n  //config.data.datasets[i].data[j] = randomScalingFactor();\n\n  \n  //config.data.labels[readings[message.destinationName][\"id\"]] = \"HIU\" +readings[message.destinationName][\"id\"] + \": \" + parseFloat(readings[message.destinationName][\"payload\"]);\n  window.myPolarArea.update();\n\n\n\nvar tno = 0;\nvar curTot = 0;\nvar curTotNo = 0;\n\nfor (var mqt in readings) {\n    \n        var v = parseFloat(readings[mqt][\"payload\"]);\n    \n\t\t\n\t\ttno++;\n\t\t\n\t\tif (v > 0.2) { curTotNo++;  curTot = curTot+v; }\n\t\t\n\t\tif (v >  peakInd) { peakInd = v;  }\n}\n\n\nif (curTot > peakTot) { peakTot = curTot;  peakTotNo=curTotNo;  }\n\ndocument.getElementById(\"tno\").innerHTML = parseInt(tno*10)/10;\ndocument.getElementById(\"curTot_t\").innerHTML = parseInt(curTot*10)/10;\ndocument.getElementById(\"curTotNo_t\").innerHTML = parseInt(curTotNo*10)/10;\ndocument.getElementById(\"peakInd_t\").innerHTML = parseInt(peakInd*10)/10;\ndocument.getElementById(\"peakTot_t\").innerHTML = parseInt(peakTot*10)/10;\ndocument.getElementById(\"peakTotNo_t\").innerHTML = parseInt(peakTotNo*10)/10;\n\n  \n//   var sortable = [];\n// \tfor (var mqt in readings) {\n// \t\tsortable.push([mqt]);\n// \t}\n\n// \tsortable.sort(function(a, b) {\n// \t\treturn a[0] > b[0];\n// \t});\n  \n  \n  \n// \tvar mql = '<table class=\"tt\"><tr><th align=\"left\">Topic</th><th>Data</th></tr>';\n\t\n// \tfor (var kk in sortable) {\n// \t\tvar k = sortable[kk][0];\n// \t\tmql += \"<tr><td>\" + k.replace(/\\//g,\" / \") + \"</td><td>\" + readings[k].payload + \"</td></tr>\";\n// \t}\n// \tmql += \"</table>\";\n\t\n\t\n// \tdocument.getElementById(\"mqlist\").innerHTML = mql;\n  \n}\n\n\n\n\n</script>\n\n\n\n<script src=\"/includes/chart.js/Chart.min.js\"></script>\n<script src=\"/includes/chart.js/utils.js\"></script>\n\n<style>\n    canvas {\n        -moz-user-select: none;\n        -webkit-user-select: none;\n        -ms-user-select: none;\n    }\n</style>\n\n\n<!-- <section style=\"height: 100vh; background: #cbced8\"> -->\n\n<!-- <p>This page recieves real-time tap use data, showing flow rates in each property as well as delivery temperatures.  -->\n\n<table width=\"100%\"><tr><td>\n   \n     \n<div id=\"canvas-holder\" style=\"width:100%;\">\n    <canvas id=\"chart-area\"></canvas>\n</div>\n\n </td><td width=\"30%\" valign=\"top\">\n\n      <table class=\"table\">\n          <tr><td width=\"50%\">Number of Systems</td><td><span id=\"tno\">0</span></td></tr>\n          <tr><td width=\"50%\">Current Total Flow</td><td><span id=\"curTot_t\">0.0</span> ltr/min (<span id=\"curTotNo_t\">0</span> running)</td></tr>\n          <tr><td width=\"50%\">Peak Total Flow</td><td><span id=\"peakTot_t\">0.0</span> ltr/min (<span id=\"peakTotNo_t\">0</span> running)</td></tr>\n          <tr><td width=\"50%\">Peak Individual Flow</td><td><span id=\"peakInd_t\">0.0</span> ltr/min</td></tr>\n          \n          \n          \n          </table>\n \n</td></tr></table>\n\n<!-- <button id=\"randomizeData\">Randomize Data</button>\n<button id=\"addData\">Add Data</button>\n<button id=\"removeData\">Remove Data</button> -->\n<script>\n    var randomScalingFactor = function() {\n        return Math.round(Math.random() * 100);\n    };\n\n    var chartColors = window.chartColors;\n    var color = Chart.helpers.color;\n    var config = {\n        data: {\n            datasets: [{\n                data: [],\n                backgroundColor: [],\n                label: 'My dataset' // for legend\n            }],\n            labels: []\n        },\n        options: {\n            responsive: true,\n            legend: {\n                position: 'left',\n            },\n            title: {\n                display: false,\n                text: 'Live DHW Data'\n            },\n            scale: {\n                ticks: {\n                    beginAtZero: true\n                },\n                reverse: false,\n            },\n            animation: {\n                animateRotate: true,\n                animateScale: false\n            }\n        }\n    };\n\n    window.onload = function() {\n        var ctx = document.getElementById('chart-area');\n        window.myPolarArea = Chart.PolarArea(ctx, config);\n    };\n\n    // document.getElementById('randomizeData').addEventListener('click', function() {\n    //     config.data.datasets.forEach(function(piece, i) {\n    //         piece.data.forEach(function(value, j) {\n    //             config.data.datasets[i].data[j] = randomScalingFactor();\n    //         });\n    //     });\n    //     window.myPolarArea.update();\n    // });\n\n    var colorNames = Object.keys(window.chartColors);\n    // document.getElementById('addData').addEventListener('click', function() {\n    //     if (config.data.datasets.length > 0) {\n    //         config.data.labels.push('data #' + config.data.labels.length);\n    //         config.data.datasets.forEach(function(dataset) {\n    //             var colorName = colorNames[config.data.labels.length % colorNames.length];\n    //             dataset.backgroundColor.push(window.chartColors[colorName]);\n    //             dataset.data.push(randomScalingFactor());\n    //         });\n    //         window.myPolarArea.update();\n    //     }\n    // });\n    // document.getElementById('removeData').addEventListener('click', function() {\n    //     config.data.labels.pop(); // remove the label first\n    //     config.data.datasets.forEach(function(dataset) {\n    //         dataset.backgroundColor.pop();\n    //         dataset.data.pop();\n    //     });\n    //     window.myPolarArea.update();\n    // });\n</script>\n\n<!--<div id=\"mqlist\">-->\n<!-- Waiting for data... -->\n<!--</div>-->\n\n</body>\n\n</html>","output":"str","x":383,"y":3507,"wires":[["b1b85bd8.718be8"]]},{"id":"edd49736.d11fd","type":"comment","z":"512e2cc3.3a1bdc","name":"The global.pages object stores collections of sections to form a top-level web page.","info":"","x":352,"y":3889,"wires":[]},{"id":"5fa73555.16541c","type":"mqtt-broker","z":"","name":"","broker":"mqtt.heatweb.com","port":"10031","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"b650ce61.a54ba","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"e80025eb.47b288","type":"ui_group","z":"","name":"Default","tab":"f7d30b1e.2b7528","order":1,"disp":false,"width":"24","collapse":false},{"id":"f7d30b1e.2b7528","type":"ui_tab","z":"","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]